package com.apobates.forum.toro.tuple.strategy;

import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * 抽像的Triple异步策略
 * @param <L> 左对象类型
 * @param <M> 中对象类型
 * @param <R> 右对象类型
 * @param <E> 中对象查询函数参数的类型
 * @param <U> 右对象查询函数参数的类型
 *
 * @author xiaofanku@live.cn
 * @since 20220517
 */
public class AbstractTripleFutureStrategy<L,M,R,E,U> extends AbstractTupleStrategy {
    private final int timeout;
    private final TimeUnit unit;
    private final static Logger logger = LoggerFactory.getLogger(AbstractTripleFutureStrategy.class);

    public AbstractTripleFutureStrategy(int timeout, TimeUnit unit) {
        this.timeout = timeout;
        this.unit = unit;
    }

    public AbstractTripleFutureStrategy() {
        this(1, TimeUnit.SECONDS);
    }

    @Override
    protected String getSentinel() {
        return "TripleFuture";
    }

    public int getTimeout() {
        return timeout;
    }

    public TimeUnit getUnit() {
        return unit;
    }

    /**
     * 返回聚合结果
     * @param lFuture 左对象的Future实例
     * @param middleFun 中对象查询函数
     * @param rightFun 右对象查询函数
     * @param arguments 连接参数集合
     * @return
     */
    protected Triple<L, M, R> get(CompletableFuture<L> lFuture, Function<E, M> middleFun, Function<U, R> rightFun, Map<String, String> arguments) {
        // 左-右
        CompletableFuture<Pair<L, R>> lrFuture = lFuture.thenCompose((L leftObj) -> CompletableFuture.supplyAsync(() -> {
            U rightArg = null;
            try{
                Object rightArgVal = getBaseSelectVal(leftObj, arguments.get("rightAttr"), arguments.get("rightAttrType"), "右");
                rightArg = (U)rightArgVal;
            }catch (Exception e){
                logger.debug("[TS][TripleFuture]获取右对象的查询参数时出现异常:"+e.getMessage());
            }
            return Pair.of(leftObj, rightFun.apply(rightArg));
        }).completeOnTimeout(null, this.timeout, this.unit)).orTimeout(1, TimeUnit.SECONDS);
        // 中
        CompletableFuture<M> middleFuture = lFuture.thenCompose((L leftObj) -> CompletableFuture.supplyAsync(() -> {
            E middleArg = null;
            try{
                Object middleArgVal = getBaseSelectVal(leftObj, arguments.get("middleAttr"), arguments.get("middleAttrType"), "中");
                middleArg = (E)middleArgVal;
            }catch (Exception e){
                logger.debug("[TS][TripleFuture]获取中对象的查询参数时出现异常:"+e.getMessage());
            }
            return middleFun.apply(middleArg);
        }).completeOnTimeout(null, this.timeout, this.unit)).orTimeout(1, TimeUnit.SECONDS);
        return lrFuture.thenCombine(middleFuture, (lrPair, middleIns)-> {
            return Triple.of(lrPair.getLeft(), middleIns, lrPair.getRight());
        }).orTimeout(this.timeout, this.unit).join();
    }
}
